/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.execution;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ResourceBundle;
import java.io.IOException;
import org.openide.TopManager;
import org.openide.execution.*;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.windows.InputOutput;
import org.openide.util.io.FoldingIOException;
/** Executes a class in a thread in the current VM.
*
* @author Ales Novak
*/
public class ThreadExecutor extends Executor {
/** generated Serialized Version UID */
static final long serialVersionUID = -7160546092135474445L;
// the bundle to use
static ResourceBundle bundle;
/** Create a new thread executor. */
public ThreadExecutor() {
}
/*
* @param ctx @see ExecutionEngine.Context
* @param info an ExecInfo instance describing executed class
*/
public ExecutorTask execute(ExecInfo info) throws IOException {
TERunnable run = new TERunnable(info);
ExecutorTask ret;
InputOutput inout = (needsIO() ? null : InputOutput.NULL);
synchronized (run) {
ret = TopManager.getDefault().getExecutionEngine().execute(info.getClassName(), run, inout);
run.setInputOutput(ret.getInputOutput());
try {
run.wait(); // wait for arbitrary exceptions during executing run
Throwable t = run.getException();
if (t != null) {
if (! (t instanceof ThreadDeath)) {
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else if (t instanceof Error) {
throw (Error) t;
} else if (t instanceof IOException) {
throw (IOException) t;
} else {
throw new FoldingIOException(t);
}
}
}
} catch (InterruptedException e) {
throw new FoldingIOException(e);
}
}
return ret;
}
/** notifies about exception
* @param t is a Throwable
*/
private static void notifyException(final Throwable t) {
//javax.swing.SwingUtilities.invokeLater(new Runnable() {
// public void run() {
TopManager.getDefault().notifyException(t);
// }
// });
}
/* @return name */
protected String displayName() {
return getString("InternalExecution");
}
public HelpCtx getHelpCtx () {
return new HelpCtx (ThreadExecutor.class);
}
/** Subclasses of the executor can override this method
* to check loaded class before its main method is invoked.
*
* @param clazz
* @exception IOException
*/
protected void checkClass(Class clazz) throws IOException {
// find main (String[])
final java.lang.reflect.Method method;
try {
method = clazz.getDeclaredMethod("main", new Class[] { String[].class }); // NOI18N
} catch (NoSuchMethodException e) {
if (e.getLocalizedMessage() == null) {
e = new NoSuchMethodException(getString("EXC_NoSuchMethodException"));
}
throw new FoldingIOException(e);
}
if (! java.lang.reflect.Modifier.isStatic(method.getModifiers())) {
throw new IllegalArgumentException("java.lang.reflect.Modifier.isStatic(" + method + ") == false"); // NOI18N
}
if (! java.lang.reflect.Modifier.isPublic(method.getModifiers())) {
throw new IllegalArgumentException("java.lang.reflect.Modifier.isPublic(" + method + ") == false"); // NOI18N
}
if (method.getReturnType() != Void.TYPE) {
throw new IllegalArgumentException(method + ".getReturnType() != Void.TYPE"); // NOI18N
}
}
/** Invokes main method of the class with given parameters.
*
* @param clazz
* @param params
*/
protected void executeClass(Class clazz, String[] params) {
try {
final java.lang.reflect.Method method = clazz.getDeclaredMethod("main", new Class[] { params.getClass () }); // NOI18N
method.setAccessible(true); // needs a permission
method.invoke (null, new Object[] { params });
} catch (java.lang.reflect.InvocationTargetException ex) {
if (! (ex.getTargetException() instanceof ThreadDeath))
ex.getTargetException().printStackTrace();
} catch (Exception e) {
e.printStackTrace(); // is redirected since executed under EE
}
}
/** @return localized string */
static String getString(String s) {
if (bundle == null) {
bundle = NbBundle.getBundle(ThreadExecutor.class);
}
return bundle.getString(s);
}
/* ThreadExecutor runnable
* Its run method loads needed class, notifies waiting thread and executes main method of the class.
*/
private class TERunnable implements Runnable {
private Throwable exception;
private ExecInfo info;
private InputOutput io;
TERunnable(ExecInfo info) {
this.info = info;
}
public synchronized void run() {
String className = info.getClassName();
final String[] params = info.getArguments();
Class clazz = null;
try {
NbClassLoader loader = new NbClassLoader(io);
clazz = loader.loadClass(className);
if (clazz == null) {
throw new IOException(); // [PENDING]
}
if (clazz.getClassLoader() != loader) {
TopManager.getDefault().setStatusText(clazz + getString("MSG_Inv_CLoader") + clazz.getClassLoader());
}
checkClass(clazz);
} catch (ThreadDeath td) {
throw td;
} catch (Throwable e) {
exception = e;
return;
} finally {
notifyAll();
}
executeClass(clazz, params);
}
public Throwable getException() {
return exception;
}
public void setInputOutput(InputOutput io) {
this.io = io;
}
}
}
/*
* Log
* 18 Gandalf 1.17 1/17/00 Ales Novak #5399
* 17 Gandalf 1.16 1/12/00 Ian Formanek NOI18N
* 16 Gandalf 1.15 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 15 Gandalf 1.14 10/7/99 Jesse Glick displayName should be
* protected, not public.
* 14 Gandalf 1.13 10/5/99 Ales Novak exec is divided into two
* phases
* 13 Gandalf 1.12 10/1/99 Ales Novak major change of
* execution
* 12 Gandalf 1.11 8/6/99 Ales Novak invalid classloader msg
* 11 Gandalf 1.10 7/2/99 Jesse Glick Help IDs for debugger &
* executor types.
* 10 Gandalf 1.9 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 9 Gandalf 1.8 4/8/99 Ales Novak
* 8 Gandalf 1.7 4/6/99 Ales Novak
* 7 Gandalf 1.6 3/31/99 Ales Novak
* 6 Gandalf 1.5 3/26/99 Jaroslav Tulach
* 5 Gandalf 1.4 3/23/99 Jesse Glick [JavaDoc]
* 4 Gandalf 1.3 3/23/99 Jesse Glick [JavaDoc]
* 3 Gandalf 1.2 3/4/99 Ales Novak
* 2 Gandalf 1.1 1/14/99 Ales Novak
* 1 Gandalf 1.0 1/5/99 Ian Formanek
* $
*/